/* Module default_pager */

#ifndef _GNU_SOURCE
#define _GNU_SOURCE 1
#endif

#define EXPORT_BOOLEAN
#include <mach/boolean.h>
#include <mach/kern_return.h>
#include <mach/message.h>
#include <mach/mig_errors.h>
#include <mach/mig_support.h>

#ifndef	mig_internal
#define	mig_internal	static
#endif

#ifndef	mig_external
#define mig_external
#endif

#ifndef	TypeCheck
#define	TypeCheck 1
#endif

#ifndef	UseExternRCSId
#define	UseExternRCSId		1
#endif

#define BAD_TYPECHECK(type, check) ({\
  union { mach_msg_type_t t; unsigned32_t w; } _t, _c;\
  _t.t = *(type); _c.t = *(check); _t.w != _c.w; })
#define msgh_request_port	msgh_local_port
#define MACH_MSGH_BITS_REQUEST(bits)	MACH_MSGH_BITS_LOCAL(bits)
#define msgh_reply_port		msgh_remote_port
#define MACH_MSGH_BITS_REPLY(bits)	MACH_MSGH_BITS_REMOTE(bits)

#include <mach/std_types.h>
#include <mach/mach_types.h>
#include <mach/default_pager_types.h>

/* Routine default_pager_object_create */
mig_internal void _Xdefault_pager_object_create
	(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
{
	typedef struct {
		mach_msg_header_t Head;
		mach_msg_type_t object_sizeType;
		vm_size_t object_size;
	} Request;

	typedef struct {
		mach_msg_header_t Head;
		mach_msg_type_t RetCodeType;
		kern_return_t RetCode;
		mach_msg_type_t memory_objectType;
		memory_object_t memory_object;
	} Reply;

	register Request *In0P = (Request *) InHeadP;
	register Reply *OutP = (Reply *) OutHeadP;
	mig_external kern_return_t default_pager_object_create
		(mach_port_t default_pager, memory_object_t *memory_object, vm_size_t object_size);

	auto const mach_msg_type_t object_sizeCheck = {
		/* msgt_name = */		2,
		/* msgt_size = */		32,
		/* msgt_number = */		1,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		FALSE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	};

	auto const mach_msg_type_t memory_objectType = {
		/* msgt_name = */		20,
		/* msgt_size = */		32,
		/* msgt_number = */		1,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		FALSE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	};

#if	TypeCheck
	if ((In0P->Head.msgh_size != 32) ||
	    (In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX))
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
#endif	/* TypeCheck */

#if	TypeCheck
	if (BAD_TYPECHECK(&In0P->object_sizeType, &object_sizeCheck))
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
#endif	/* TypeCheck */

	OutP->RetCode = default_pager_object_create(In0P->Head.msgh_request_port, &OutP->memory_object, In0P->object_size);
	if (OutP->RetCode != KERN_SUCCESS)
		return;

	OutP->Head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;
	OutP->Head.msgh_size = 40;

	OutP->memory_objectType = memory_objectType;
}

/* Routine default_pager_info */
mig_internal void _Xdefault_pager_info
	(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
{
	typedef struct {
		mach_msg_header_t Head;
	} Request;

	typedef struct {
		mach_msg_header_t Head;
		mach_msg_type_t RetCodeType;
		kern_return_t RetCode;
		mach_msg_type_t infoType;
		default_pager_info_t info;
	} Reply;

	register Request *In0P = (Request *) InHeadP;
	register Reply *OutP = (Reply *) OutHeadP;
	mig_external kern_return_t default_pager_info
		(mach_port_t default_pager, default_pager_info_t *info);

	auto const mach_msg_type_t infoType = {
		/* msgt_name = */		2,
		/* msgt_size = */		32,
		/* msgt_number = */		3,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		FALSE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	};

#if	TypeCheck
	if ((In0P->Head.msgh_size != 24) ||
	    (In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX))
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
#endif	/* TypeCheck */

	OutP->RetCode = default_pager_info(In0P->Head.msgh_request_port, &OutP->info);
	if (OutP->RetCode != KERN_SUCCESS)
		return;

	OutP->Head.msgh_size = 48;

	OutP->infoType = infoType;
}

/* Routine default_pager_objects */
mig_internal void _Xdefault_pager_objects
	(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
{
	typedef struct {
		mach_msg_header_t Head;
		mach_msg_type_t objectsCntType;
		mach_msg_type_number_t objectsCnt;
		mach_msg_type_t portsCntType;
		mach_msg_type_number_t portsCnt;
	} Request;

	typedef struct {
		mach_msg_header_t Head;
		mach_msg_type_t RetCodeType;
		kern_return_t RetCode;
		mach_msg_type_long_t objectsType;
		default_pager_object_t objects[256];
		mach_msg_type_long_t portsType;
		mach_port_t ports[512];
	} Reply;

	register Request *In0P = (Request *) InHeadP;
	register Reply *OutP = (Reply *) OutHeadP;
	mig_external kern_return_t default_pager_objects
		(mach_port_t default_pager, default_pager_object_array_t *objects, mach_msg_type_number_t *objectsCnt, mach_port_array_t *ports, mach_msg_type_number_t *portsCnt);

	unsigned int msgh_size;
	unsigned int msgh_size_delta;

	auto const mach_msg_type_t objectsCntCheck = {
		/* msgt_name = */		MACH_MSG_TYPE_INTEGER_32,
		/* msgt_size = */		32,
		/* msgt_number = */		1,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		FALSE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	};

	auto const mach_msg_type_t portsCntCheck = {
		/* msgt_name = */		MACH_MSG_TYPE_INTEGER_32,
		/* msgt_size = */		32,
		/* msgt_number = */		1,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		FALSE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	};

	auto const mach_msg_type_long_t objectsType = {
	{
		/* msgt_name = */		0,
		/* msgt_size = */		0,
		/* msgt_number = */		0,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		TRUE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	},
		/* msgtl_name = */	2,
		/* msgtl_size = */	32,
		/* msgtl_number = */	512,
	};

	auto const mach_msg_type_long_t portsType = {
	{
		/* msgt_name = */		0,
		/* msgt_size = */		0,
		/* msgt_number = */		0,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		TRUE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	},
		/* msgtl_name = */	17,
		/* msgtl_size = */	32,
		/* msgtl_number = */	512,
	};

	mach_msg_type_number_t objectsCnt;
	mach_port_t ports[512];
	mach_msg_type_number_t portsCnt;

	default_pager_object_t *objectsP;
	mach_port_t *portsP;

#if	TypeCheck
	if ((In0P->Head.msgh_size != 40) ||
	    (In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX))
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
#endif	/* TypeCheck */

#if	TypeCheck
	if (BAD_TYPECHECK(&In0P->objectsCntType, &objectsCntCheck))
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
#endif	/* TypeCheck */

#if	TypeCheck
	if (BAD_TYPECHECK(&In0P->portsCntType, &portsCntCheck))
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
#endif	/* TypeCheck */

	objectsP = OutP->objects;
	objectsCnt = 256;
	if (In0P->objectsCnt < objectsCnt)
		objectsCnt = In0P->objectsCnt;

	portsP = ports;
	portsCnt = 512;
	if (In0P->portsCnt < portsCnt)
		portsCnt = In0P->portsCnt;

	OutP->RetCode = default_pager_objects(In0P->Head.msgh_request_port, &objectsP, &objectsCnt, &portsP, &portsCnt);
	if (OutP->RetCode != KERN_SUCCESS)
		return;

	OutP->Head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;

	OutP->objectsType = objectsType;
	if (objectsP != OutP->objects) {
		OutP->objectsType.msgtl_header.msgt_inline = FALSE;
		OutP->objectsType.msgtl_header.msgt_deallocate = TRUE;
		*((default_pager_object_t **)OutP->objects) = objectsP;
	}

	OutP->objectsType.msgtl_number = 2 * objectsCnt;
	msgh_size_delta = (OutP->objectsType.msgtl_header.msgt_inline) ? 8 * objectsCnt : sizeof(default_pager_object_t *);
	msgh_size = 56 + msgh_size_delta;
	OutP = (Reply *) ((char *) OutP + msgh_size_delta - 2048);

	OutP->portsType = portsType;

	if (portsP != ports) {
		OutP->portsType.msgtl_header.msgt_inline = FALSE;
		OutP->portsType.msgtl_header.msgt_deallocate = TRUE;
		*((mach_port_t **)OutP->ports) = portsP;
	}
	else {
		memcpy(OutP->ports, ports, 4 * portsCnt);
	}

	OutP->portsType.msgtl_number = portsCnt;
	msgh_size += (OutP->portsType.msgtl_header.msgt_inline) ? 4 * portsCnt : sizeof(mach_port_t *);

	OutP = (Reply *) OutHeadP;
	OutP->Head.msgh_size = msgh_size;
}

/* Routine default_pager_object_pages */
mig_internal void _Xdefault_pager_object_pages
	(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
{
	typedef struct {
		mach_msg_header_t Head;
		mach_msg_type_t memory_objectType;
		mach_port_t memory_object;
		mach_msg_type_t pagesCntType;
		mach_msg_type_number_t pagesCnt;
	} Request;

	typedef struct {
		mach_msg_header_t Head;
		mach_msg_type_t RetCodeType;
		kern_return_t RetCode;
		mach_msg_type_long_t pagesType;
		default_pager_page_t pages[512];
	} Reply;

	register Request *In0P = (Request *) InHeadP;
	register Reply *OutP = (Reply *) OutHeadP;
	mig_external kern_return_t default_pager_object_pages
		(mach_port_t default_pager, mach_port_t memory_object, default_pager_page_array_t *pages, mach_msg_type_number_t *pagesCnt);

	boolean_t msgh_simple;
	auto const mach_msg_type_t memory_objectCheck = {
		/* msgt_name = */		17,
		/* msgt_size = */		32,
		/* msgt_number = */		1,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		FALSE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	};

	auto const mach_msg_type_t pagesCntCheck = {
		/* msgt_name = */		MACH_MSG_TYPE_INTEGER_32,
		/* msgt_size = */		32,
		/* msgt_number = */		1,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		FALSE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	};

	auto const mach_msg_type_long_t pagesType = {
	{
		/* msgt_name = */		0,
		/* msgt_size = */		0,
		/* msgt_number = */		0,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		TRUE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	},
		/* msgtl_name = */	2,
		/* msgtl_size = */	32,
		/* msgtl_number = */	512,
	};

	mach_msg_type_number_t pagesCnt;

	default_pager_page_t *pagesP;

#if	TypeCheck
	if ((In0P->Head.msgh_size != 40) ||
	    !(In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX))
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
#endif	/* TypeCheck */

#if	TypeCheck
	if (BAD_TYPECHECK(&In0P->memory_objectType, &memory_objectCheck))
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
#endif	/* TypeCheck */

#if	TypeCheck
	if (BAD_TYPECHECK(&In0P->pagesCntType, &pagesCntCheck))
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
#endif	/* TypeCheck */

	pagesP = OutP->pages;
	pagesCnt = 512;
	if (In0P->pagesCnt < pagesCnt)
		pagesCnt = In0P->pagesCnt;

	OutP->RetCode = default_pager_object_pages(In0P->Head.msgh_request_port, In0P->memory_object, &pagesP, &pagesCnt);
	if (OutP->RetCode != KERN_SUCCESS)
		return;

	msgh_simple = TRUE;

	OutP->pagesType = pagesType;
	if (pagesP != OutP->pages) {
		OutP->pagesType.msgtl_header.msgt_inline = FALSE;
		OutP->pagesType.msgtl_header.msgt_deallocate = TRUE;
		*((default_pager_page_t **)OutP->pages) = pagesP;
		msgh_simple = FALSE;
	}

	OutP->pagesType.msgtl_number = pagesCnt;
	OutP->Head.msgh_size = 44 + ((OutP->pagesType.msgtl_header.msgt_inline) ? 4 * pagesCnt : sizeof(default_pager_page_t *));

	if (!msgh_simple)
		OutP->Head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;
}

/* Routine default_pager_paging_file */
mig_internal void _Xdefault_pager_paging_file
	(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
{
	typedef struct {
		mach_msg_header_t Head;
		mach_msg_type_t master_device_portType;
		mach_port_t master_device_port;
		mach_msg_type_long_t filenameType;
		default_pager_filename_t filename;
		mach_msg_type_t addType;
		boolean_t add;
	} Request;

	typedef struct {
		mach_msg_header_t Head;
		mach_msg_type_t RetCodeType;
		kern_return_t RetCode;
	} Reply;

	register Request *In0P = (Request *) InHeadP;
	register Reply *OutP = (Reply *) OutHeadP;
	mig_external kern_return_t default_pager_paging_file
		(mach_port_t default_pager, mach_port_t master_device_port, default_pager_filename_t filename, boolean_t add);

	auto const mach_msg_type_t master_device_portCheck = {
		/* msgt_name = */		17,
		/* msgt_size = */		32,
		/* msgt_number = */		1,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		FALSE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	};

	auto const mach_msg_type_t addCheck = {
		/* msgt_name = */		0,
		/* msgt_size = */		32,
		/* msgt_number = */		1,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		FALSE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	};

#if	TypeCheck
	if ((In0P->Head.msgh_size != 308) ||
	    !(In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX))
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
#endif	/* TypeCheck */

#if	TypeCheck
	if (BAD_TYPECHECK(&In0P->master_device_portType, &master_device_portCheck))
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
#endif	/* TypeCheck */

#if	TypeCheck
	if ((In0P->filenameType.msgtl_header.msgt_inline != TRUE) ||
	    (In0P->filenameType.msgtl_header.msgt_longform != TRUE) ||
	    (In0P->filenameType.msgtl_name != 12) ||
	    (In0P->filenameType.msgtl_number != 1) ||
	    (In0P->filenameType.msgtl_size != 2048))
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
#endif	/* TypeCheck */

#if	TypeCheck
	if (BAD_TYPECHECK(&In0P->addType, &addCheck))
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
#endif	/* TypeCheck */

	OutP->RetCode = default_pager_paging_file(In0P->Head.msgh_request_port, In0P->master_device_port, In0P->filename, In0P->add);
}

/* Routine default_pager_register_fileserver */
mig_internal void _Xdefault_pager_register_fileserver
	(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
{
	typedef struct {
		mach_msg_header_t Head;
		mach_msg_type_t fileserver_portType;
		mach_port_t fileserver_port;
	} Request;

	typedef struct {
		mach_msg_header_t Head;
		mach_msg_type_t RetCodeType;
		kern_return_t RetCode;
	} Reply;

	register Request *In0P = (Request *) InHeadP;
	register Reply *OutP = (Reply *) OutHeadP;
	mig_external kern_return_t default_pager_register_fileserver
		(mach_port_t default_pager, mach_port_t fileserver_port);

	auto const mach_msg_type_t fileserver_portCheck = {
		/* msgt_name = */		17,
		/* msgt_size = */		32,
		/* msgt_number = */		1,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		FALSE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	};

#if	TypeCheck
	if ((In0P->Head.msgh_size != 32) ||
	    !(In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX))
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
#endif	/* TypeCheck */

#if	TypeCheck
	if (BAD_TYPECHECK(&In0P->fileserver_portType, &fileserver_portCheck))
		{ OutP->RetCode = MIG_BAD_ARGUMENTS; return; }
#endif	/* TypeCheck */

	OutP->RetCode = default_pager_register_fileserver(In0P->Head.msgh_request_port, In0P->fileserver_port);
}

static mig_routine_t default_pager_server_routines[] = {
		_Xdefault_pager_object_create,
		_Xdefault_pager_info,
		_Xdefault_pager_objects,
		_Xdefault_pager_object_pages,
		_Xdefault_pager_paging_file,
		_Xdefault_pager_register_fileserver,
};

mig_external boolean_t default_pager_server
	(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
{
	register mach_msg_header_t *InP =  InHeadP;
	register mig_reply_header_t *OutP = (mig_reply_header_t *) OutHeadP;

	auto const mach_msg_type_t RetCodeType = {
		/* msgt_name = */		MACH_MSG_TYPE_INTEGER_32,
		/* msgt_size = */		32,
		/* msgt_number = */		1,
		/* msgt_inline = */		TRUE,
		/* msgt_longform = */		FALSE,
		/* msgt_deallocate = */		FALSE,
		/* msgt_unused = */		0
	};

	register mig_routine_t routine;

	OutP->Head.msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REPLY(InP->msgh_bits), 0);
	OutP->Head.msgh_size = sizeof *OutP;
	OutP->Head.msgh_remote_port = InP->msgh_reply_port;
	OutP->Head.msgh_local_port = MACH_PORT_NULL;
	OutP->Head.msgh_seqno = 0;
	OutP->Head.msgh_id = InP->msgh_id + 100;

	OutP->RetCodeType = RetCodeType;

	if ((InP->msgh_id > 2280) || (InP->msgh_id < 2275) ||
	    ((routine = default_pager_server_routines[InP->msgh_id - 2275]) == 0)) {
		OutP->RetCode = MIG_BAD_ID;
		return FALSE;
	}
	(*routine) (InP, &OutP->Head);
	return TRUE;
}

mig_external mig_routine_t default_pager_server_routine
	(const mach_msg_header_t *InHeadP)
{
	register int msgh_id;

	msgh_id = InHeadP->msgh_id - 2275;

	if ((msgh_id > 5) || (msgh_id < 0))
		return 0;

	return default_pager_server_routines[msgh_id];
}

